package com.chinatechstar.component.socketio;

import com.chinatechstar.admin.entity.SysUser;
import com.chinatechstar.admin.mapper.SysUserMapper;
import com.chinatechstar.cache.redis.constants.ApplicationConstants;
import com.chinatechstar.cache.redis.util.RedisUtils;
import com.chinatechstar.component.commons.utils.*;
import com.chinatechstar.notification.entity.SysMsg;
import com.chinatechstar.notification.mapper.SysMsgMapper;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author Rei
 */
@Component
public class NettySocketEventHandler {
    private static final SequenceGenerator SEQUENCE_GENERATOR = new SequenceGenerator();
    private final Logger logger = LoggerFactory.getLogger(NettySocketEventHandler.class);

    public static final String COMMON_MSG = "commonMsg";

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private SysMsgMapper sysMsgMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SocketIOServer socketIOServer;

    @OnConnect
    public void onConnect(SocketIOClient client) {
        String accessToken = client.getHandshakeData().getSingleUrlParam("token");
        if (StrUtils.isNullOrEmpty(accessToken)) {
            return;
        }

        OAuth2Authentication authentication = Oauth2Utils.getAuthenticationInOauth2Server(accessToken);
        if (authentication == null || !authentication.isAuthenticated()) {
            return;
        }

        String username = authentication.getName();
        if (StrUtils.isNullOrEmpty(username)) {
            return;
        }

        redisUtils.hset(ApplicationConstants.SOCKET_CLIENT_USER_SESSION, username, client.getSessionId().toString());
        redisUtils.hset(ApplicationConstants.SOCKET_CLIENT_SESSION_USER, client.getSessionId().toString(), username);
        int msgNotReadCount = sysMsgMapper.countMsgToUserNotRead(username);
        Map<String, Object> map = new HashMap<>();
        map.put("status", 200);
        map.put("message", "OK");
        map.put("notReadMsgCount", msgNotReadCount);
        map.put("lastOneMsg", null);
        client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));

        String businessId = client.getHandshakeData().getSingleUrlParam("businessId");
        if (!StrUtils.isNullOrEmpty(businessId)) {
            socketIOServer.addNamespace("/ns_comMsg_" + businessId);
        }
    }

    @OnDisconnect
    public void onDisConnect(SocketIOClient client) {
        String clientSessionId = client.getSessionId().toString();
        String redisUsername = redisUtils.hget(ApplicationConstants.SOCKET_CLIENT_SESSION_USER, clientSessionId);
        if (redisUtils.hexists(ApplicationConstants.SOCKET_CLIENT_USER_SESSION, redisUsername)) {
            redisUtils.hdel(ApplicationConstants.SOCKET_CLIENT_USER_SESSION, redisUsername);
        }
        if (redisUtils.hexists(ApplicationConstants.SOCKET_CLIENT_SESSION_USER, clientSessionId)) {
            redisUtils.hdel(ApplicationConstants.SOCKET_CLIENT_SESSION_USER, clientSessionId);
        }
    }

    // 自定义一个notification事件，也可以自定义其它任何名字的事件
    @OnEvent("commonMsg")
    public void commonMsg(SocketIOClient client, AckRequest request, MsgBody msgBody) {
        Map<String, Object> map = new HashMap<>();

        if (!COMMON_MSG.equals(msgBody.getEventType())) {
            map.put("message", "事件类型不匹配");
            map.put("status", 1001);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            return;
        }

        String username = redisUtils.hget(ApplicationConstants.SOCKET_CLIENT_SESSION_USER, client.getSessionId().toString());
        if (StrUtils.isNullOrEmpty(username)) {
            map.put("message", "您的会话已过期");
            map.put("status", 1002);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            return;
        }
        SysUser userEntityFrom = sysUserMapper.getUserByUsername(username);
        if (userEntityFrom == null) {
            map.put("message", "您的用户信息异常，未找到您的身份");
            map.put("status", 1090);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            return;
        }

        String msgTitle = (String) msgBody.getPayload().get("msgTitle");
        if (StrUtils.isNullOrEmpty(msgTitle)) {
            map.put("message", "msgTitle 未设置");
            map.put("status", 1003);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            return;
        }

        String msgContent = (String) msgBody.getPayload().get("msgContent");
        if (StrUtils.isNullOrEmpty(msgContent)) {
            map.put("message", "msgContent 未设置");
            map.put("status", 1004);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            return;
        }

        String msgType = (String) msgBody.getPayload().get("msgType");
        if (StrUtils.isNullOrEmpty(msgType)) {
            map.put("message", "msgType 未设置");
            map.put("status", 1005);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            return;
        }

        String msgAction = (String) msgBody.getPayload().get("msgAction");
        String msgActionParam = (String) msgBody.getPayload().get("msgActionParam");


        String msgToUserId = (String) msgBody.getPayload().get("msgToUserId");
        if (StrUtils.isNullOrEmpty(msgToUserId)) {
            map.put("message", "msgToUserId 未设置");
            map.put("status", 1010);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            return;
        }
        SysUser userEntityTo = sysUserMapper.getUserByUsername(msgToUserId);
        if (userEntityTo == null) {
            map.put("message", "目标用户不存在");
            map.put("status", 1011);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            return;
        }

        SysMsg msgEntity = new SysMsg();
        msgEntity.setId(SEQUENCE_GENERATOR.nextId());
        msgEntity.setMsgFromUserId(userEntityFrom.getId());
        msgEntity.setMsgFromUsername(userEntityFrom.getUsername());
        msgEntity.setMsgFromNickname(userEntityFrom.getNickname());
        msgEntity.setMsgToUserId(userEntityTo.getId());
        msgEntity.setMsgToUsername(userEntityTo.getUsername());
        msgEntity.setMsgToNickname(userEntityTo.getNickname());
        msgEntity.setMsgStatus(2);
        msgEntity.setMsgType(msgType);
        msgEntity.setMsgTitle(msgTitle);
        msgEntity.setMsgContent(msgContent);
        msgEntity.setMsgSendTime(DateUtils.asTimestamp(new Date()));
        msgEntity.setMsgAction(!StrUtils.isNullOrEmpty(msgAction) ? msgAction : null);
        msgEntity.setMsgActionParam(!StrUtils.isNullOrEmpty(msgActionParam) ? msgActionParam : null);
        sysMsgMapper.insertSysMsg(msgEntity);

        String redisSession = redisUtils.hget(ApplicationConstants.SOCKET_CLIENT_USER_SESSION, msgToUserId);
        if (!StrUtils.isNullOrEmpty(redisSession)) {
            UUID uuid = UUID.fromString(redisSession);
            SocketIOClient socketIOClientTo = socketIOServer.getClient(uuid);
            if (socketIOClientTo != null) {
                int msgNotReadCount = sysMsgMapper.countMsgToUserNotRead(msgToUserId);
                map.put("status", 200);
                map.put("message", "OK");
                map.put("notReadMsgCount", msgNotReadCount);
                map.put("lastOneMsg", new Object());

                socketIOClientTo.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            } else {
                map.put("message", "消息已发送到目标用户，但用户不在线");
                map.put("status", 200);
                client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
            }
        } else {
            map.put("message", "消息已发送到目标用户，但用户不在线");
            map.put("status", 200);
            client.sendEvent(COMMON_MSG, new MsgBody(COMMON_MSG, map));
        }
    }
}
